package cn.com.generaldata.os.service.indicator_evaluation.industry_structure_analysis;

import org.apache.commons.lang3.Validate;
import org.nutz.dao.Chain;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.entity.Record;
import org.nutz.dao.sql.Criteria;
import org.nutz.lang.random.R;

import cn.com.generaldata.jsme_indicator_system.entity.IndicatorEvaluation;
import cn.com.generaldata.os.service.indicator_constant.ProvinceIndicatorConstant;
import cn.com.generaldata.os.service.indicator_evaluation.CalculateService;
import cn.com.generaldata.os.service.indicator_evaluation.CalculateServiceHelper;
import cn.com.generaldata.os.util.BeanMapper;
import cn.com.generaldata.os.vo.IndicatorAccountVO;

/**
 * 海洋三次产业结构相似系数指标计算类.
 */
public class StructureSimilarityCoefficientCalculateService implements CalculateService {

	private String GOPIndustryName = ProvinceIndicatorConstant.GOP_INDICATOR_NAME;

	private Dao dao;

	private Dao indicatorSystemDao;

	private CalculateServiceHelper helper;

	@Override
	public void calculateIndicator(IndicatorEvaluation indicator, IndicatorAccountVO indicatorAccountVO) {

		Double jsGOP = getProvinceGOP(indicatorAccountVO);
		Validate.isTrue(jsGOP != null);
		for (String otherProvince : ProvinceIndicatorConstant.OTHER_COASTAL_PROVINCES) {
			IndicatorAccountVO otherProvinceVO = BeanMapper.map(indicatorAccountVO, IndicatorAccountVO.class);
			otherProvinceVO.setAreaId(otherProvince);
			Double otherProvinceGOP = getProvinceGOP(otherProvinceVO);
			if (otherProvinceGOP == null) {
				continue;
			}
			Double numerator = 0d;
			Double jsProportionSum = 0d;
			Double otherProportionSum = 0d;
			for (String indicatorName : ProvinceIndicatorConstant.THREE_INDUSTRY_STRUCT_ADDVALUE) {
				Double jsAddValueOfIndustry = getProvinceAddValueOfIndustry(indicatorAccountVO, indicatorName);
				Double otherAddValueOfIndustry = getProvinceAddValueOfIndustry(otherProvinceVO, indicatorName);
				if (jsAddValueOfIndustry == null || otherAddValueOfIndustry == null) {
					continue;
				}
				numerator += (jsAddValueOfIndustry / jsGOP)
						* (otherAddValueOfIndustry / otherProvinceGOP);

				jsProportionSum += Math.pow(jsAddValueOfIndustry / jsGOP, 2);
				otherProportionSum += Math.pow(otherAddValueOfIndustry / otherProvinceGOP, 2);

			}

			Double denominator = Math.sqrt(jsProportionSum * otherProportionSum);
			Double result = numerator / denominator;

			saveResult(indicatorAccountVO.getYear(), indicatorAccountVO.getAreaId(), otherProvince, result);
		}
	}

	/**
	 * 保存指标结果.
	 * 
	 * @param indicatorAccountVO
	 * @param result
	 */
	private void saveResult(int year, String selfAreaId, String referAreaId, Double result) {
		Criteria cri = getIndicatorDataCri(year, selfAreaId, referAreaId);
		Record record = dao.fetch("tbl_indicator_iscr", cri);
		if (record != null) {
			dao.clear("tbl_indicator_iscr", cri);
		}
		Chain chain = Chain.make("id", R.UU16());
		chain.add("year", year);
		chain.add("self_area_id", selfAreaId);
		chain.add("refer_area_id", referAreaId);

		chain.add("similar_coefficient", String.format("%.10f", result));

		dao.insert("tbl_indicator_iscr", chain);
	}

	private Criteria getIndicatorDataCri(int year, String selfAreaId, String referAreaId) {
		Criteria cri = Cnd.cri();
		cri.where().and("year", "=", year);
		cri.where().and("self_area_id", "=", selfAreaId);
		cri.where().and("refer_area_id", "=", referAreaId);
		return cri;
	}

	/**
	 * 获得省级三次海洋产业增加值
	 * 
	 * @param indicatorAccountVO
	 * @param indicator
	 * @return
	 */
	private Double getProvinceAddValueOfIndustry(IndicatorAccountVO indicatorAccountVO, String indicatorName) {
		Double inputOrAccountingIndicatorValue = helper.getInputOrAccountingIndicatorValue(indicatorAccountVO,
				indicatorAccountVO.getYear(), indicatorName);
		Validate.isTrue(inputOrAccountingIndicatorValue != null);
		return inputOrAccountingIndicatorValue;
	}

	/**
	 * 获得省级的海洋生产总值
	 * 
	 * @param indicatorAccountVO
	 * @param indicator
	 * @return
	 */
	private Double getProvinceGOP(IndicatorAccountVO indicatorAccountVO) {
		Double inputOrAccountingIndicatorValue = helper.getInputOrAccountingIndicatorValue(indicatorAccountVO,
				indicatorAccountVO.getYear(), GOPIndustryName);
		return inputOrAccountingIndicatorValue;
	}

	@Override
	public void setDao(Dao dao) {
		this.dao = dao;
	}

	@Override
	public void setIndicatorSystemDao(Dao indicatorSystemDao) {
		this.indicatorSystemDao = indicatorSystemDao;
	}

	@Override
	public void setCalculateServiceHelper(CalculateServiceHelper calculateServiceHelper) {
		helper = calculateServiceHelper;
	}

}
